#include "NPCManager.h"
#include "Terrain.h"

NPCManager::NPCManager()
    : m_pDevice(NULL)
    , m_pTerrain(NULL)
    , m_maxNPCs(30)
{
}

NPCManager::~NPCManager()
{
    Cleanup();
}

bool NPCManager::Initialize(LPDIRECT3DDEVICE9 device, int maxNPCs, Terrain* terrain)
{
    m_pDevice = device;
    m_pTerrain = terrain;
    m_maxNPCs = maxNPCs;

    // Create spawn points (7个重生点，全部靠近中心区域，5秒重生时间)
    // 四个角的重生点往中心靠拢（从100/900改为200/800）
    AddSpawnPoint(D3DXVECTOR3(200.0f, 0.0f, 200.0f), 5.0f);  // 左上（靠近中心）
    AddSpawnPoint(D3DXVECTOR3(800.0f, 0.0f, 200.0f), 5.0f);  // 右上（靠近中心）
    AddSpawnPoint(D3DXVECTOR3(800.0f, 0.0f, 800.0f), 5.0f);  // 右下（靠近中心）
    AddSpawnPoint(D3DXVECTOR3(200.0f, 0.0f, 800.0f), 5.0f);  // 左下（靠近中心）
    AddSpawnPoint(D3DXVECTOR3(500.0f, 0.0f, 500.0f), 5.0f);  // 正中心
    // 新增2个重生点（中心区域周围）
    AddSpawnPoint(D3DXVECTOR3(400.0f, 0.0f, 600.0f), 5.0f);  // 中心偏左下
    AddSpawnPoint(D3DXVECTOR3(600.0f, 0.0f, 400.0f), 5.0f);  // 中心偏右上

    // Spawn initial NPCs (1 per spawn point, total will match maxNPCs)
    int npcsToSpawn = (m_maxNPCs < (int)m_spawnPoints.size()) ? m_maxNPCs : (int)m_spawnPoints.size();

    for (int i = 0; i < npcsToSpawn; i++)
    {
        NPC* npc = new NPC();
        D3DXVECTOR3 spawnPos = m_spawnPoints[i].position +
            D3DXVECTOR3((float)(rand() % 40 - 20), 0.0f, (float)(rand() % 40 - 20));

        // Adjust Y coordinate to terrain height
        if (m_pTerrain)
        {
            float terrainHeight = m_pTerrain->GetHeight(spawnPos.x, spawnPos.z);
            spawnPos.y = terrainHeight + 5.0f;  // 5.0f is half of NPC height (10.0f box)
        }

        if (npc->Initialize(device, spawnPos))
        {
            npc->SetTerrain(m_pTerrain);
            m_npcs.push_back(npc);
            // 将 NPC 关联到重生点
            m_spawnPoints[i].assignedNPC = npc;
        }
        else
        {
            delete npc;
        }
    }

    // Create NPC groups (3-4 groups)
    CreateGroups(3);

    return true;
}

void NPCManager::Update(float deltaTime, GameObject* playerTarget, const std::vector<GameObject*>& obstacles)
{
    // Update all NPCs
    for (size_t i = 0; i < m_npcs.size(); i++)
    {
        if (!m_npcs[i]->IsDead())
        {
            m_npcs[i]->SetTarget(playerTarget);
            m_npcs[i]->SetObstacles(&obstacles);
            m_npcs[i]->Update(deltaTime);
        }
    }

    // Update groups
    for (size_t i = 0; i < m_groups.size(); i++)
    {
        m_groups[i]->SetGroupTarget(playerTarget);
        m_groups[i]->Update(deltaTime);
    }

    // Check respawns
    CheckRespawns(deltaTime);
}

void NPCManager::RenderAll(LPDIRECT3DDEVICE9 device)
{
    for (size_t i = 0; i < m_npcs.size(); i++)
    {
        if (!m_npcs[i]->IsDead())
        {
            m_npcs[i]->Render(device);
        }
    }
}

void NPCManager::AddSpawnPoint(const D3DXVECTOR3& position, float respawnTime)
{
    m_spawnPoints.push_back(SpawnPoint(position, respawnTime));
}

void NPCManager::CheckRespawns(float deltaTime)
{
    // Update spawn point timers
    for (size_t i = 0; i < m_spawnPoints.size(); i++)
    {
        SpawnPoint& sp = m_spawnPoints[i];

        // Check if assigned NPC is dead
        if (sp.assignedNPC && sp.assignedNPC->IsDead())
        {
            sp.currentTime += deltaTime;

            // Respawn when timer is up
            if (sp.currentTime >= sp.respawnTime)
            {
                // Check if we're under the limit
                if (GetAliveNPCCount() < m_maxNPCs)
                {
                    RespawnNPC(sp);
                    sp.currentTime = 0.0f;
                }
            }
        }
    }
}

void NPCManager::RespawnNPC(SpawnPoint& sp)
{
    if (sp.assignedNPC)
    {
        // Adjust spawn position to terrain height
        D3DXVECTOR3 spawnPos = sp.position;
        if (m_pTerrain)
        {
            float terrainHeight = m_pTerrain->GetHeight(spawnPos.x, spawnPos.z);
            spawnPos.y = terrainHeight + 5.0f;  // 5.0f is half of NPC height
        }

        // Reset the NPC
        sp.assignedNPC->Initialize(m_pDevice, spawnPos);
        sp.assignedNPC->SetTerrain(m_pTerrain);
    }
}

void NPCManager::CreateGroups(int groupCount)
{
    // Clean up existing groups
    for (size_t i = 0; i < m_groups.size(); i++)
    {
        delete m_groups[i];
    }
    m_groups.clear();

    // Create new groups
    for (int i = 0; i < groupCount; i++)
    {
        m_groups.push_back(new NPCGroup());
    }

    // Assign NPCs to groups
    for (size_t i = 0; i < m_npcs.size(); i++)
    {
        int groupIndex = i % groupCount;
        m_groups[groupIndex]->AddNPC(m_npcs[i]);
    }
}

int NPCManager::GetAliveNPCCount() const
{
    int count = 0;
    for (size_t i = 0; i < m_npcs.size(); i++)
    {
        if (!m_npcs[i]->IsDead())
            count++;
    }
    return count;
}

void NPCManager::Cleanup()
{
    // Clean up NPCs
    for (size_t i = 0; i < m_npcs.size(); i++)
    {
        m_npcs[i]->Cleanup();
        delete m_npcs[i];
    }
    m_npcs.clear();

    // Clean up groups
    for (size_t i = 0; i < m_groups.size(); i++)
    {
        delete m_groups[i];
    }
    m_groups.clear();

    m_spawnPoints.clear();
}
